//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "DomainPDBAtom.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <math.h>

#include <iostream>

#include <zlib.h>
#include <fstream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHLINE 5000
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
DomainPDBAtom::DomainPDBAtom () {
  
  this->domain      = new String ();
  
  this->filenameIn  = new String ();
  this->filenameOut = new String ();

  this->chain       = new String ();
  this->segments    = new TListE <SegmentCDDF> ();   

  this->listATOM    = new TListE <String> ();
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
DomainPDBAtom::DomainPDBAtom (const DomainPDBAtom& domainPDBAtom) {
  
  this->domain      = new String (domainPDBAtom.domain);
  
  this->filenameIn  = new String (domainPDBAtom.filenameIn);
  this->filenameOut = new String (domainPDBAtom.filenameOut);

  this->chain       = new String (domainPDBAtom.chain);
  this->segments    = new TListE <SegmentCDDF> (domainPDBAtom.segments);

  this->listATOM    = new TListE <String> (domainPDBAtom.listATOM);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
DomainPDBAtom::DomainPDBAtom (const DomainPDBAtom* domainPDBAtom) {
  
  this->domain      = new String (domainPDBAtom->domain);
  
  this->filenameIn  = new String (domainPDBAtom->filenameIn);
  this->filenameOut = new String (domainPDBAtom->filenameOut);

  this->chain       = new String (domainPDBAtom->chain);
  this->segments    = new TListE <SegmentCDDF> (domainPDBAtom->segments);

  this->listATOM    = new TListE <String> (domainPDBAtom->listATOM);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
DomainPDBAtom::~DomainPDBAtom () {
  
  if (this->domain)      delete this->domain;
  
  if (this->filenameIn)  delete this->filenameIn;
  if (this->filenameOut) delete this->filenameOut;

  if (this->chain)       delete this->chain;
  if (this->segments)    delete this->segments;

  if (this->listATOM)    delete this->listATOM;
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DomainPDBAtom::Domain (String* domain) {
  
  if (domain) this->domain->In(domain);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DomainPDBAtom::FilenameIn (String* filenameIn) {
  
  if (filenameIn) this->filenameIn->In(filenameIn);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DomainPDBAtom::FilenameOut (String* filenameOut) {
  
  if (filenameOut) this->filenameOut->In(filenameOut);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DomainPDBAtom::Chain (String* chain) {
  
  if (chain) this->chain->In(chain);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DomainPDBAtom::Segments (TListE <SegmentCDDF>* segments) {
  
  if (segments) *(this->segments) = *(segments);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void DomainPDBAtom::ListATOM (TListE <String>* listATOM) {
  
  if (listATOM) *(this->listATOM) = *(listATOM);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* DomainPDBAtom::Domain (void) {
  
  return this->domain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* DomainPDBAtom::FilenameIn (void) {
  
  return this->filenameIn;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* DomainPDBAtom::FilenameOut (void) {
  
  return this->filenameOut;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* DomainPDBAtom::Chain (void) {
  
  return this->chain;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <SegmentCDDF>* DomainPDBAtom::Segments (void) {
  
  return this->segments;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
TListE <String>* DomainPDBAtom::ListATOM (void) {
  
  return this->listATOM;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool DomainPDBAtom::LoadData (void) {
  
  if (!this->filenameIn || !this->filenameIn->Length() || 
      !this->domain     || !this->domain->Length()     ||
      !this->segments   || !this->segments->Length())
    return false;
  
  String* domain = this->domain->SubStr(4, 5);
  
  this->listATOM->Clear();
  this->Chain(domain);
  
  if (domain) delete domain;
  
  gzFile pdbFile = gzopen(this->filenameIn->Out(), "rb9");
  
  if (!pdbFile) return false;
  
  char   buffer[LENGTHLINE + 1];
  
  while (!gzeof(pdbFile)) {
    
    gzgets(pdbFile, buffer, LENGTHLINE);
    
    if ((!strncmp(buffer, "ATOM", strlen("ATOM"))) && 
        (buffer[21] == (this->chain->Out())[0])    && 
        (this->ResidueContainingSegment(buffer))) {
      
      String* line = new String(buffer);
      this->listATOM->Add(line);
      
    }
    
    if (!strncmp(buffer, "ENDMDL", strlen("ENDMDL")))
      break;
    
  }

  gzclose(pdbFile);
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool DomainPDBAtom::OutFile (void) {
  
  if (!this->filenameOut || !this->filenameOut->Length())
    return false;
  
  fstream pdbDomainFile;
  
  pdbDomainFile.open(this->filenameOut->Out(), fstream::out);
  
  this->listATOM->SetInitial();
  while (this->listATOM->SetNext())
    pdbDomainFile << this->listATOM->GetCurrent()->Out();
  
  pdbDomainFile.close();
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool DomainPDBAtom::ResidueContainingSegment (char* record) {
  
  if (!record || !this->segments || !this->segments->Length()) return false;
  
  bool    isContained = false;
  String* data        = new String (record);
  String* resPos      = data->SubStr(22, 26);
  int     residuePos  = atoi(resPos->Out());
  
  this->segments->SetInitial();
  
  while (this->segments->SetNext()) {
    
    SegmentCDDF* currentSegmentCDDF = this->segments->GetCurrent();
    
    if (!currentSegmentCDDF) continue;
    
    if (currentSegmentCDDF->RangeStart() <= residuePos && currentSegmentCDDF->RangeEnd() >= residuePos) {
      isContained = true;
      break;
    }
    
    
  }
  
  if (resPos) delete resPos;
  if (data)   delete data;
  
  return isContained;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
DomainPDBAtom DomainPDBAtom::operator= (const DomainPDBAtom& domainPDBAtom) {
  
  this->domain->In(domainPDBAtom.domain);
  
  this->filenameIn->In(domainPDBAtom.filenameIn);
  this->filenameOut->In(domainPDBAtom.filenameOut);
  
  this->chain->In(domainPDBAtom.chain);
  *(this->segments) = *(domainPDBAtom.segments);   
  
  *(this->listATOM) = *(domainPDBAtom.listATOM);   

  return *this;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
